#!/bin/bash

IFS=$'\n'

# Get device path
get_dev_path() {
	echo /sys/bus/$1/devices/$2
}

# Get DPAA ethernet device path
get_dpaa_dev_path() {
	get_dev_path "platform" $1
}

# Probe driver of device
dev_drv_probe() {
	local bus
	local dev
	bus=${1%%/devices/*}
	dev=${1##*/devices/}
	echo $dev > $bus/drivers_probe
}

# Bind device to driver
bind_dev_to_drv() {
	local dev
	local drv
	dev=${1##*/devices/}
	drv=$(readlink -e $1/driver)
	if [ "${drv##*/drivers/}" != "$2" ]; then
		echo $dev > $drv/unbind
	fi
	echo $2 > $1/driver_override
}

# Unbind device from driver
unbind_dev_from_drv() {
	local dev
	local drv
	dev=${1##*/devices/}
	drv=$(readlink -e $1/driver)
	if [ "$drv" != "" ]; then
		echo $dev > $drv/unbind
	fi
	echo "" > $1/driver_override
}

# Test if device bind to driver
if_dev_bind_to_drv() {
	local drv
	local str
	drv=$(readlink -e $1/driver)
	read -d '' str < $1/driver_override
	if [ "${drv##*/drivers/}" == "$2" -o "$str" == "$2" ]; then
		true
	else
		false
	fi
}

# Get OF path from device path
get_of_path() {
	echo $1/of_node
}

# Get device path from phandle
get_dev_path_by_phandle() {
	local d
	for d in $(find $1 -maxdepth 1 -type l); do
		if cmp -s $(get_of_path $d)/phandle $2 -n 4 -i 0:$3; then
			echo $d
			break
		fi
	done
}

# Get fman MAC device path from DPAA ethernet name
get_fman_mac_dev_path() {
	get_dev_path_by_phandle $(get_dpaa_dev_path) $(get_of_path $(get_dpaa_dev_path $1))/fsl,fman-mac 0
}

# Get mac address from fman MAC path
get_mac_addr() {
	hexdump -v -e '/1 "%02x:"' $(get_of_path $1)/local-mac-address 2>/dev/null | cut -f -6 -d ':'
}

# Get phy connection type from fman MAC path
get_phy_connection_type() {
	local str
	read -d '' str 2>/dev/null < $(get_of_path $1)/phy-connection-type
	echo $str
}

# Get interface name from fman MAC path
get_if_name() {
	local fm_path
	local fm_id
	local mac_id
	fm_path=$(readlink -e $1/../)
	fm_id=$((0x$(hexdump -v -e '/1 "%02x"' $(get_of_path $1)/cell-index)+1))
	fm_id=$((0x$(hexdump -v -e '/1 "%02x"' $(get_of_path $fm_path)/cell-index)+1))
	mac_id=$((0x$(hexdump -v -e '/1 "%02x"' $(get_of_path $1)/cell-index)+1))
	printf "fm%u-mac%u" $fm_id $mac_id
}

# Get PHY device name from fman MAC path
get_phy_name() {
	local phy_dev_path
	local phy_node
	phy_dev_path=$(get_dev_path_by_phandle $(get_dev_path "mdio_bus") $(get_of_path $1)/phy-handle 0)
	phy_node=$(readlink -e $(get_of_path $phy_dev_path))
	echo ${phy_node##*/}
}

# Print help
print_help() {
	echo "Tool for bind DPAA ethernet devices"
	echo "Usage:"
	echo "Bind ethernet devices"
	echo "$0 ethernet@x ethernet@y"
	echo
	echo "Unbind ethernet devices"
	echo "$0 -u ethernet@x ethernet@y"
	echo
	echo "Show ethernet devices already bind"
	echo "$0"
	echo
	echo "Acceptable arguments are ethernet@x"
	echo -e "\tethernet@x = This specify that 1 ethernet object to be bind or unbind."
}

# Echo in red
echo_red() {
	echo -e '\033[0;31m'$*'\033[0m'
}

# Echo in green
echo_green() {
	echo -e '\033[0;32m'$*'\033[0m'
}

unset drv
unset unbind
unset ether_list

drv="sb_dpaa-netdev"
declare -a ether_list

while [ $# -ne 0 ]; do
	case $1 in
	-h)
		print_help
		exit
		;;
	-u)
		unbind="yes"
		shift
		;;
	*)
		break
		;;
	esac
done

echo -e "\n\n######################### Configured Interfaces #########################\n\n"
printf "%-21s %-21s %-21s %-21s %-21s %-25s\n" "Interface Name" "Device Name" "Connection Type" "Phy Device Name" "Mac Address"
printf "%-21s %-21s %-21s %-21s %-21s %-25s\n" "==============" "===========" "===============" "===============" "=================="


if [ $# -gt 0 ]; then
	for obj in $*; do
		type=${obj%@*}
		dev=soc:fsl,dpaa:$obj
		mac_path=$(get_fman_mac_dev_path $dev)
		if [ "$type" != "ethernet" -o "$mac_path" == "" ]; then
			echo_red "\n\tInvalid Argument \"$obj\"\n\n"
			exit 1
		fi
	done

	for obj in $*; do
		dev=soc:fsl,dpaa:$obj
		ether_list[${#ether_list[*]}]=$obj
		mac_path=$(get_fman_mac_dev_path $dev)
		if_name=$(get_if_name $mac_path)
		conn_type=$(get_phy_connection_type $mac_path)
		phy_name=$(get_phy_name $mac_path)
		mac_addr=$(get_mac_addr $mac_path)
		[ "$conn_type" != "" ] || conn_type="<Unknown>"
		[ "$phy_name" != "" ] || phy_name="<Unknown>"
		[ "$mac_addr" != "" ] || mac_addr="<Unknown>"
		printf "%-21s %-21s %-21s %-21s %-25s\n" $if_name $obj $conn_type $phy_name $mac_addr
	done

	echo -e "\n"

	for obj in ${ether_list[*]}; do
		dev=soc:fsl,dpaa:$obj
		dev_path=$(get_dpaa_dev_path $dev)
		if [ "${unbind-no}" == "no" ]; then
			bind_dev_to_drv $dev_path $drv
			dev_drv_probe $dev_path
			echo_green "Bind \"$obj\" to \"$drv\" driver"
		elif if_dev_bind_to_drv $dev_path $drv; then
			unbind_dev_from_drv $dev_path
			echo_green "Unbind \"$obj\" from \"$drv\" driver"
		fi
	done
else
	for d in $(find $(get_dpaa_dev_path) -maxdepth 1 -type l); do
		if if_dev_bind_to_drv $d $drv; then
			dev=${d#$(get_dpaa_dev_path)}
			obj=${dev#soc:fsl,dpaa:}
			mac_path=$(get_fman_mac_dev_path $dev)
			if_name=$(get_if_name $mac_path)
			conn_type=$(get_phy_connection_type $mac_path)
			phy_name=$(get_phy_name $mac_path)
			mac_addr=$(get_mac_addr $mac_path)
			[ "$conn_type" != "" ] || conn_type="<Unknown>"
			[ "$phy_name" != "" ] || phy_name="<Unknown>"
			[ "$mac_addr" != "" ] || mac_addr="<Unknown>"
			printf "%-21s %-21s %-21s %-21s %-25s\n" $if_name $obj $conn_type $phy_name $mac_addr
		fi
	done
fi
